package com.googlecode.cnasort.cc.rmi.server.ihm;

import javax.swing.JPanel;
import java.awt.CardLayout;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;

import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Point;

import javax.swing.JButton;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Logger;

import com.googlecode.cnasort.cc.rmi.server.core.Message;

import javax.swing.JTextPane;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class ServerJPanel extends JPanel
{
    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger( ServerJPanel.class );
    private static final String DISPLAY_PANEL = "DISPLAY_PANEL";
    private static final Object CONFIG_PANEL = "CONFIG_PANEL";

    private JTable table;
    private JButton startButton;
    private ServerCommand serverCommand;
    private List<NetworkInfos> networkInfosList;
    private JTextPane textPane;
    private CardLayout cardLayout;

    private static class NetworkInfos {
        private NetworkInterface networkInterface;
        private InterfaceAddress interfaceAddress;
        private InetAddress      inetAddress;

        public NetworkInfos(
            NetworkInterface networkInterface,
            InterfaceAddress interfaceAddress,
            InetAddress      inetAddress
            )
        {
            this.networkInterface = networkInterface;
            this.interfaceAddress = interfaceAddress;
            this.inetAddress      = inetAddress;
        }

        public NetworkInterface getNetworkInterface() {
            return networkInterface;
        }

        public InterfaceAddress getInterfaceAddress() {
            return interfaceAddress;
        }

        public InetAddress getInetAddress() {
            return inetAddress;
        }
    }

    private enum Columnns {
        networkInterface("Interface"),
        ipAddress("IP address"),
        hostName("Host name"),
        prefix("Prefix"),
        broadcastAddress("Broadcast address");

        private String label;

        private Columnns(String label)
        {
            this.label = label;
        }

        public String getLabel()
        {
             return label;
         }

        public Object getValue( NetworkInfos networkInfos )
        {
            switch( this ) {
                case networkInterface:
                    return networkInfos.getNetworkInterface().getName();
                case ipAddress:
                    return networkInfos.getInetAddress().getHostAddress();
                case hostName:
                    return networkInfos.getInetAddress().getHostName();
                case prefix:
                    return networkInfos.getInterfaceAddress().getNetworkPrefixLength();
                case broadcastAddress:
                    return networkInfos.getInterfaceAddress().getBroadcast().getHostAddress();
                }
            return null;
         }
    }

    private class MyTableModel extends AbstractTableModel
    {
        private static final long serialVersionUID = 1L;


        public MyTableModel() throws SocketException
        {
               networkInfosList = new ArrayList<>();

            for( final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces( ); interfaces.hasMoreElements(); ) {
                final NetworkInterface cur = interfaces.nextElement( );

                for( final InterfaceAddress addr : cur.getInterfaceAddresses( ) ) {
                    final InetAddress inet_addr = addr.getAddress( );

                    if( !( inet_addr instanceof Inet4Address ) ) {
                        continue;
                        }

                    networkInfosList.add( new NetworkInfos(cur, addr, inet_addr) );
                    }
                }
        }

        @Override
        public int getRowCount()
        {
            return networkInfosList.size();
        }

        @Override
        public int getColumnCount()
        {
            return Columnns.values().length;
        }

        @Override
        public String getColumnName( final int columnIndex )
        {
            return Columnns.values()[ columnIndex ].getLabel();
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex)
        {
            NetworkInfos networkInfos = networkInfosList.get( rowIndex );

            return Columnns.values()[ columnIndex ].getValue( networkInfos );
        }
    }

    private class RowListener implements ListSelectionListener
    {
        @Override
        public void valueChanged( ListSelectionEvent event )
        {
             if (event.getValueIsAdjusting()) {
                return;
                }

             int selected = table.getSelectedRow();

             startButton.setEnabled( selected >= 0 );
        }
    }

    /**
     * Create the panel.
     * @throws SocketException
     */
    public ServerJPanel( ServerCommand serverCommand ) throws SocketException
    {
        this.serverCommand = serverCommand;
        this.textPane = new JTextPane();
        this.serverCommand.setMessage( new Message() {
            private void append(String message)
            {
                textPane.setText( textPane.getText() + message + '\n' );
            }
            @Override
            public void info(String message)
            {
                logger.info( message );
                append( message );
            }

            @Override
            public void warn(String message)
            {
                logger.warn( message );
                append( message );
            }

            @Override
            public void warn(String message, Throwable exception) {
                logger.warn( message, exception );

                StringWriter sw = new StringWriter();
                exception.printStackTrace( new PrintWriter( sw ) );

                append( message + "\n" + sw.getBuffer().toString() );
            }
            
			@Override
			public boolean isTraceEnabled() {
				return logger.isTraceEnabled();
			}
			
			@Override
			public void trace(String message) {
                logger.warn( message );
                append( message );
			}
        });

        cardLayout = new CardLayout(0, 0);
        setLayout( cardLayout );

        {
            JPanel panel1 = new JPanel();
            add(panel1, CONFIG_PANEL );
            GridBagLayout gbl_panel1 = new GridBagLayout();
            gbl_panel1.columnWidths = new int[]{200, 50, 0};
            gbl_panel1.rowHeights = new int[]{20, 20, 150, 0};
            gbl_panel1.columnWeights = new double[]{1.0, 0.0, Double.MIN_VALUE};
            gbl_panel1.rowWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE};
            panel1.setLayout(gbl_panel1);

            {
                JScrollPane scrollPane = new JScrollPane();
                GridBagConstraints gbc_scrollPane = new GridBagConstraints();
                gbc_scrollPane.insets = new Insets(0, 0, 0, 5);
                gbc_scrollPane.gridheight = 3;
                gbc_scrollPane.fill = GridBagConstraints.BOTH;
                gbc_scrollPane.gridx = 0;
                gbc_scrollPane.gridy = 0;
                panel1.add(scrollPane, gbc_scrollPane);

                table = new JTable();
                table.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        // get the coordinates of the mouse click
                        Point p        = e.getPoint();
                        int   rowIndex = table.rowAtPoint( p );

                        if( rowIndex == -1) {
                            // outside a cel !
                            return;
                        }

                        if (e.getClickCount() == 2){
                            // Double clic !
                            onStart( rowIndex );
                            }
                    }
                });
                table.setModel( new MyTableModel() );
                table.setAutoResizeMode( JTable.AUTO_RESIZE_ALL_COLUMNS );
                table.getSelectionModel().addListSelectionListener(new RowListener());
                table.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );

                scrollPane.setViewportView(table);

                {
                    startButton = new JButton("Start");
                    startButton.setEnabled(false);
                    startButton.addActionListener(new ActionListener() {
                        @Override
                     public void actionPerformed(ActionEvent e) {
                            onStart();
                        }
                    });
                    GridBagConstraints gbc_startButton = new GridBagConstraints();
                    gbc_startButton.insets = new Insets(0, 0, 5, 0);
                    gbc_startButton.fill = GridBagConstraints.BOTH;
                    gbc_startButton.gridy = 0;
                    gbc_startButton.gridx = 1;
                    panel1.add(startButton, gbc_startButton);
                }

                {
                    JButton quitButton = new JButton("Quit");
                    quitButton.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            onQuit();
                        }
                    });
                    GridBagConstraints gbc_quitButton = new GridBagConstraints();
                    gbc_quitButton.fill = GridBagConstraints.HORIZONTAL;
                    gbc_quitButton.insets = new Insets(0, 0, 5, 0);
                    gbc_quitButton.gridx = 1;
                    gbc_quitButton.gridy = 1;
                    panel1.add(quitButton, gbc_quitButton);
                }
            }
        }

        {
            JPanel panel2 = new JPanel();
            add(panel2, DISPLAY_PANEL );
            GridBagLayout gbl_panel2 = new GridBagLayout();
            gbl_panel2.columnWidths = new int[]{100, 50, 50, 100};
            gbl_panel2.rowHeights = new int[]{0, 0, 0};
            gbl_panel2.columnWeights = new double[]{1.0, 0.0, 0.0, 1.0};
            gbl_panel2.rowWeights = new double[]{1.0, 0.0, Double.MIN_VALUE};
            panel2.setLayout(gbl_panel2);
            {
                JButton hideButton = new JButton("Hide");
                hideButton.setEnabled(false);
                hideButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        onHide();
                    }
                });
                GridBagConstraints gbc_hideButton = new GridBagConstraints();
                gbc_hideButton.fill = GridBagConstraints.HORIZONTAL;
                gbc_hideButton.insets = new Insets(0, 0, 0, 5);
                gbc_hideButton.gridx = 1;
                gbc_hideButton.gridy = 1;
                panel2.add(hideButton, gbc_hideButton);
            }
            {
                JButton quit2Button = new JButton("Quit");
                quit2Button.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        onQuit();
                    }
                });
                GridBagConstraints gbc_quit2Button = new GridBagConstraints();
                gbc_quit2Button.fill = GridBagConstraints.HORIZONTAL;
                gbc_quit2Button.insets = new Insets(0, 0, 0, 5);
                gbc_quit2Button.gridx = 2;
                gbc_quit2Button.gridy = 1;
                panel2.add(quit2Button, gbc_quit2Button);
            }
            {
                JScrollPane scrollPane = new JScrollPane();
                GridBagConstraints gbc_scrollPane = new GridBagConstraints();
                gbc_scrollPane.insets = new Insets(0, 0, 5, 0);
                gbc_scrollPane.gridwidth = 4;
                gbc_scrollPane.fill = GridBagConstraints.BOTH;
                gbc_scrollPane.gridx = 0;
                gbc_scrollPane.gridy = 0;
                panel2.add(scrollPane, gbc_scrollPane);
                {
                    //JTextPane textPane = new JTextPane();
                    textPane.setEditable(false);
                    scrollPane.setViewportView(textPane);
                }
            }
        }
    }

    protected void onHide()
    {
        // TODO Auto-generated method stub
    }

    protected void onQuit()
    {
        System.exit(0); // TODO bad way to quit
    }

    protected void onStart()
    {
        logger.info( "onStart()" );

        onStart( table.getSelectedRow() );
    }

    protected void onStart( int selectedRowIndex )
    {
        logger.info( "onStart( " + selectedRowIndex  + " )" );

        NetworkInfos networkInfos = networkInfosList.get( selectedRowIndex );

        cardLayout.show( this, DISPLAY_PANEL );
        serverCommand.lauch( networkInfos.getInetAddress() );
    }
}
